using UnityEngine;
using UnityEngine.UIElements;

/// <summary>
/// Ball 类表示游戏中的一个球体对象，负责球的运动、碰撞、粒子效果等逻辑
/// </summary>
public class Ball : MonoBehaviour
{
    // 序列化字段，可在 Unity 编辑器中设置，并带有最小值限制
    [SerializeField, Min(0f)] 
    float
        maxXSpeed = 20f,          // 球在 X 轴方向的最大速度
        maxStartXSpeed = 2f,      // 游戏开始时，球在 X 轴方向的最大初始速度
        constantYSpeed = 10f,     // 球在 Y 轴方向的恒定速度
        extents = 0.5f;           // 球的碰撞范围或视觉效果范围

    [SerializeField] 
    ParticleSystem 
        bounceParticleSystem,     // 球碰撞时产生的粒子系统
        startParticleSystem,      // 游戏开始时播放的粒子系统
        trailParticleSystem;      // 球移动时留下的轨迹粒子系统

    [SerializeField] 
    int
        bounceParticleEmission = 20,   // 每次碰撞时，bounce 粒子系统发射的粒子数量
        startParticleEmission = 100;   // 游戏开始时，start 粒子系统发射的粒子数量
    
    Vector2 
        position, // 球的当前位置
        velocity; // 球的当前速度
    
    public float Extents => extents; // 获取球的碰撞范围大小

    public Vector2 Position => position; // 获取球的当前位置

    public Vector2 Velocity => velocity; // 获取球的当前速度
    
    void Awake () 
    {
        // 初始时将球的游戏对象设为不可见
        gameObject.SetActive(false);
    }

    /// <summary>
    /// 开始一场新游戏时调用，重置球的状态
    /// </summary>
    public void StartNewGame ()
    {
        // 将球的位置重置为原点 (0, 0)
        position = Vector2.zero;

        // 更更新球以及其粒子系统的位置
        UpdateVisualization();

        // 设置球的初始 X 方向速度为随机值
        velocity.x = Random.Range(-maxStartXSpeed, maxStartXSpeed);

        // 设置球的初始 Y 方向速度为负的恒定速度（通常是向上发射）
        velocity.y = -constantYSpeed;

        // 激活球的游戏对象
        gameObject.SetActive(true);

        // 触发开始游戏的粒子特效
        startParticleSystem.Emit(startParticleEmission);

        // 开启球的轨迹粒子效果
        SetTrailEmission(true);

        // 播放轨迹粒子系统动画
        trailParticleSystem.Play();
    }

    /// <summary>
    /// 结束游戏时调用，隐藏球并停止轨迹效果
    /// </summary>
    public void EndGame ()
    {
        // 将球的 X 坐标重置为 0
        position.x = 0f;

        // 隐藏球的游戏对象
        gameObject.SetActive(false);

        // 关闭轨迹粒子效果
        SetTrailEmission(false);
    }

    /// <summary>
    /// 设置球的 X 位置和 X 方向速度
    /// </summary>
    public void SetXPositionAndSpeed (float start, float speedFactor, float deltaTime)
    {
        // 设置 X 方向的速度
        velocity.x = maxXSpeed * speedFactor;

        // 根据起始位置、速度和时间差计算出新的 X 坐标
        position.x = start + velocity.x * deltaTime;
    }

    /// <summary>
    /// 每帧调用，根据当前速度更新球的位置
    /// </summary>
    public void Move () 
    {
        position += velocity * Time.deltaTime;
    }

    /// <summary>
    /// 更新球以及其粒子系统的位置
    /// </summary>
    public void UpdateVisualization () 
    {
        // 设置球、轨迹粒子系统的本地位置
        trailParticleSystem.transform.localPosition 
            = transform.localPosition 
                = new Vector3(position.x, 0f, position.y); 
    }

    /// <summary>
    /// 当球在 X 轴方向发生碰撞（比如撞墙）时调用
    /// </summary>
    /// <param name="boundary"></param>
    public void BounceX (float boundary)
    {
        // 计算碰撞后，球还需要多长时间才能到达碰撞边界，用于定位粒子效果
        float durationAfterBounce = (position.x - boundary) / velocity.x;

        // 根据反射定律，将 X 方向速度反向
        position.x = 2f * boundary - position.x;
        velocity.x = -velocity.x;

        // 在碰撞点位置生成弹跳粒子特效，并设置旋转方向
        EmitBounceParticles(
            boundary,                                   // 碰撞的 X 边界位置
            position.y - velocity.y * durationAfterBounce, // 估算的 Z（高度）位置
            boundary < 0f ? 90f : 270f                  // 根据边界在左还是右，设置粒子旋转角度
        );
    }

    /// <summary>
    /// 当球在 Y 轴方向发生碰撞（比如撞天花板或地板）时调用
    /// </summary>
    public void BounceY (float boundary)
    {
        // 计算碰撞后，球还需要多长时间才能到达碰撞边界
        float durationAfterBounce = (position.y - boundary) / velocity.y;

        // 根据反射定律，将 Y 方向速度反向
        position.y = 2f * boundary - position.y;
        velocity.y = -velocity.y;

        // 在碰撞点位置生成弹跳粒子特效，并设置旋转方向
        EmitBounceParticles(
            position.x - velocity.x * durationAfterBounce, // 估算的 X 位置
            boundary,                                    // 碰撞的 Y 边界位置
            boundary < 0f ? 0f : 180f                    // 根据边界在上还是在下，设置粒子旋转角度
        );
    }

    /// <summary>
    /// 发射球碰撞时的粒子特效，设置粒子发射位置与旋转角度
    /// </summary>
    void EmitBounceParticles (float x, float z, float rotation)
    {
        // 获取 bounce 粒子系统的 Shape 模块，用于设置粒子生成的形状与位置
        ParticleSystem.ShapeModule shape = bounceParticleSystem.shape;

        // 设置粒子生成的本地位置（x, 0, z）
        shape.position = new Vector3(x, 0f, z);

        // 设置粒子生成的旋转角度（影响粒子发射方向或形状朝向）
        shape.rotation = new Vector3(0f, rotation, 0f);

        // 触发粒子系统发射指定数量的粒子
        bounceParticleSystem.Emit(bounceParticleEmission);
    }

    /// <summary>
    /// 控制轨迹粒子系统是否启用发射功能
    /// </summary>
    void SetTrailEmission (bool enabled)
    {
        // 获取轨迹粒子系统的 Emission 模块
        ParticleSystem.EmissionModule emission = trailParticleSystem.emission;

        // 设置该模块是否启用（即是否持续发射粒子）
        emission.enabled = enabled;
    }
}